package combine.utils.dao.ibatis;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.util.Assert;

import combine.utils.BaseException;
import combine.utils.DataPage;


/**
 * IBatis Dao的泛型基类.
 * <p/>
 * 继承于Spring的SqlMapClientDaoSupport,提供分页函数和若干便捷查询方法，并对返回值作了泛型类型转换.
 * 
 * @author suwei
 * @see SqlMapClientDaoSupport
 */
@SuppressWarnings("unchecked")
public class IBatisGenericDao extends  SqlSessionDaoSupport{

	public static final String POSTFIX_INSERT = "_insert";

	public static final String POSTFIX_UPDATE = "_update";

	public static final String POSTFIX_DELETE = "_delete";

	public static final String POSTFIX_DELETE_PRIAMARYKEY = "_deleteByPrimaryKey";

	public static final String POSTFIX_SELECT = "_select";

	public static final String POSTFIX_SELECTMAP = "_selectByMap";

	public static final String POSTFIX_SELECTSQL = "_selectBySql";

	public static final String POSTFIX_COUNT = "_count";

	/**
	 * 根据ID获取对象
	 * 
	 * @throws BaseException
	 * @throws SQLException 
	 */
	public <T> T get(Class<T> entityClass, Serializable id) throws BaseException, SQLException {
		T o = (T) getSqlSession().selectOne(entityClass.getName().replace(".", "_") + POSTFIX_SELECT, id);
		if (o == null)
			throw new BaseException(BaseException.DATA_NOTFOUND, "未找到实体: " + id);
		return o;
	}

	/**
	 * 获取全部对象
	 * @throws SQLException 
	 */
	public <T> List<T> getAll(Class<T> entityClass) throws SQLException {
		return getSqlSession().selectList(entityClass.getName().replace(".", "_") + POSTFIX_SELECT, null);
	}

	/**
	 * 新增对象
	 * @throws SQLException 
	 */
	public Object insert(Object o) throws SQLException {
		return getSqlSession().insert(o.getClass().getName().replace(".", "_") + POSTFIX_INSERT, o);
	}

	/**
	 * 保存对象
	 * @throws SQLException 
	 */
	public void update(Object o) throws SQLException {
		getSqlSession().update(o.getClass().getName().replace(".", "_") + POSTFIX_UPDATE, o);
	}

	/**
	 * 删除对象
	 * @throws SQLException 
	 */
	public void remove(Object o) throws SQLException {
		getSqlSession().delete(o.getClass().getName().replace(".", "_") + POSTFIX_DELETE, o);
	}

	/**
	 * 根据ID删除对象
	 * @throws SQLException 
	 */
	public <T> void removeById(Class<T> entityClass, Serializable id) throws SQLException {
		getSqlSession().delete(entityClass.getName().replace(".", "_") + POSTFIX_DELETE_PRIAMARYKEY, id);
	}

	/**
	 * map查询.
	 * 
	 * @param map
	 *            包含各种属性的查询
	 * @throws SQLException 
	 */
	public <T> List<T> find(Class<T> entityClass, Map map) throws SQLException {
		if (map == null)
			return this.getSqlSession().selectList(entityClass.getName().replace(".", "_") + POSTFIX_SELECT, null);
		else {
			map.put("findBy", "True");
			return this.getSqlSession()
					.selectList(entityClass.getName().replace(".", "_") + POSTFIX_SELECTMAP, map);
		}
	}

	/**
	 * sql 查询.
	 * 
	 * @param sql
	 *            直接sql的语句(需要防止注入式攻击)
	 * @throws SQLException 
	 */
	public <T> List<T> find(Class<T> entityClass, String sql) throws SQLException {
		Assert.hasText(sql);
		if (StringUtils.isEmpty(sql))
			return this.getSqlSession().selectList(entityClass.getName().replace(".", "_") + POSTFIX_SELECT, null);
		else
			return this.getSqlSession()
					.selectList(entityClass.getName().replace(".", "_") + POSTFIX_SELECTSQL, sql);
	}

	/**
	 * 根据属性名和属性值查询对象.
	 * 
	 * @return 符合条件的对象列表
	 * @throws SQLException 
	 */
	public <T> List<T> findBy(Class<T> entityClass, String name, Object value) throws SQLException {
		Assert.hasText(name);
		Map map = new HashMap();
		map.put(name, value);
		return find(entityClass, map);
	}

	/**
	 * 根据属性名和属性值查询对象.
	 * 
	 * @return 符合条件的唯一对象
	 */
	public <T> T findUniqueBy(Class<T> entityClass, String name, Object value) {
		Assert.hasText(name);
		Map map = new HashMap();
		try {
			PropertyUtils.getProperty(entityClass.newInstance(), name);
			map.put(name, value);
			map.put("findUniqueBy", "True");
			return (T) getSqlSession().selectOne(entityClass.getName().replace(".", "_") + POSTFIX_SELECTMAP,
					map);
		} catch (Exception e) {
			logger.error("Error when propertie on entity," + e.getMessage(), e.getCause());
			return null;
		}

	}

	/**
	 * 根据属性名和属性值以Like AnyWhere方式查询对象.
	 * @throws SQLException 
	 */
	public <T> List<T> findByLike(Class<T> entityClass, String name, String value) throws SQLException {
		Assert.hasText(name);
		Map map = new HashMap();
		map.put(name, value);
		map.put("findLikeBy", "True");
		return getSqlSession().selectList(entityClass.getName().replace(".", "_") + POSTFIX_SELECTMAP, map);

	}

//	/**
//	 * 判断对象某些属性的值在数据库中不存在重复
//	 * 
//	 * @param tableName
//	 *            数据表名字
//	 * @param names
//	 *            在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password" <br>
//	 *            FIXME how about in different schema?
//	 */
//	public boolean isNotUnique(Object entity, String tableName, String names) {
//		try {
//			String primarykey;
//			Connection con = getSqlSession().getCurrentConnection();
//			ResultSet dbMetaData = con.getMetaData().getPrimaryKeys(con.getCatalog(), null, tableName);
//			dbMetaData.next();
//			if (dbMetaData.getRow() > 0) {
//				primarykey = dbMetaData.getString(4);
//				if (names.indexOf(primarykey) > -1)
//					return false;
//			} else {
//				return true;
//			}
//
//		} catch (SQLException e) {
//			logger.error(e.getMessage(), e);
//			return false;
//		}
//		return false;
//	}

	/**
	 * 分页查询函数，使用PaginatedList.
	 * 
	 * @param pageNo
	 *            页号,从0开始.
	 * @throws SQLException
	 */
	public <T> DataPage<T> pagedQuery(String sqlName, HashMap<String, Object> hashMap, Integer pageNo, Integer pageSize)
			throws SQLException {

		if (pageNo == null || pageSize == null) {
			List list = getSqlSession().selectList(sqlName, hashMap);
			if (list == null || list.size() == 0) {
				return new DataPage();
			} else {
				return new DataPage(0, list.size(), list.size(), list);
			}
		} else {
			Assert.hasText(sqlName);
			Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
			// Count查询
			Integer totalCount = (Integer) getSqlSession().selectOne(sqlName + "_Count", hashMap);

			if (totalCount < 1) {
				return new DataPage();
			}

			// 实际查询返回分页对象
			int startIndex = DataPage.getStartOfPage(pageNo, pageSize);
			hashMap.put("startIndex", startIndex);
			hashMap.put("pageSize", pageSize);
			List<T> list = getSqlSession().selectList(sqlName, hashMap);

			return new DataPage(startIndex, totalCount, pageSize, list);
		}
	}
//
//	public String getMappedSQL(String sqlName) {
//		String sql = null;
//
//		SqlMapClientImpl sqlmap = (SqlMapClientImpl) getSqlSession();
//
//		MappedStatement stmt = sqlmap.getMappedStatement(sqlName);
//		StaticSql staticSql = (StaticSql) stmt.getSql();
//		sql = staticSql.getSql(null, null);
//		return sql;
//	}
}
